/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package com.emex.app.stuff.utils;

import java.io.File;
import java.util.regex.Pattern;

/**
 * Some useful validation utils
 * 
 * @author Sergey Karavaev
 */
public final class Validation
{
	/**
	 * Denied symbols in Windows * ? \ / : " < > |
	 */
	public static final String OS_ILLEGAL_SYMBOLS = "*?\\\\/:\"<>|";
	/**
	 * Maximal full path length
	 */
	public static final int MAX_PATH = 254;
	/**
	 * Maximal full path length for Microsoft Exel
	 */
	public static final int MAX_PATH_EXCEL = 217;
	public static final int PORT_MAX_VALUE = 65536;
	public static final int PASSWORD_MAX_LENGTH = 30;
	private static final String IP4_REGEXP = "[\\*|\\?|0|1][\\d|\\*|\\?]{0,2}|"//
			+ "25[0-5|\\*|\\?]|"//
			+ "2[0-4|\\*|\\?][\\d|\\*|\\?]|"//
			+ "[\\d|\\*|\\?]{1,2}";
	private static final String IP4 = "25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d";
	private static final String IP6_REGEXP = "[0-9a-fA-F|\\?|\\*]{1,4}";
	private static final String IP6 = "[0-9a-fA-F]{1,4}";
	private static final String ILLEGAL_IP_REGEXP = "[\\*]{1,}";
	private static final String IP4_DELIMITER = ".";
	private static final String IP6_DELIMITER = ":";

	private Validation()
	{
	}

	/**
	 * Check ip address
	 * 
	 * @param sVal
	 *             ip
	 * @param containsRegexp
	 *             allow to use regexp symbols : * and ?
	 * @return true if ok, or false if not valid
	 */
	public static boolean checkIpAddress(String sVal, boolean containsRegexp)
	{
		try
		{
			sVal = sVal.trim();
			if (sVal.isEmpty())
				return false;

			boolean valid = false;
			if (sVal.indexOf(IP4_DELIMITER) > 0)
				valid = ipv4valid(sVal, containsRegexp);
			else if (sVal.indexOf(IP6_DELIMITER) > 0)
				valid = ipv6valid(sVal, containsRegexp);

			if (!valid)
				return false;
		}
		catch (Exception e)
		{
			return false;
		}
		return true;
	}

	/**
	 * Check ip address
	 * 
	 * @param sVal ip
	 * @return true if ok, or false if not valid
	 */
	public static boolean checkIpAddress(String sVal)
	{
		return checkIpAddress(sVal, false);
	}
        
        public static boolean checkFQDN(String sVal)
        {
            return Pattern.matches("(?=^.{1,254}$)(^(?:(?!\\d+\\.)[a-zA-Z0-9_\\-]{1,63}\\.?)+(?:[a-zA-Z]{2,})$)", sVal);
        }

	/**
	 * Format IPv6 NNNN:NNNN:NNNN:NNNN:NNNN:NNNN:NNNN:NNNN
	 * 
	 * @param sVal ip
	 * @param containsRegexp
	 *             allow to use regexp symbols : * and ?
	 * @return true if ok, or false if not valid
	 */
	public static boolean ipv6valid(String sVal, boolean containsRegexp)
	{
		String[] ipv6 = sVal.trim().split(IP6_DELIMITER);
		boolean v6 = true;
		for (int i = 0; i < ipv6.length; i++)
		{
			boolean f = (ipv6[i].contains("*") || ipv6[i].contains("?")) && containsRegexp;
			v6 = v6 && (Pattern.matches(f ? IP6_REGEXP : IP6, ipv6[i]));
		}
		//ip cannot be *:*:*:*:*:*:*:*
		v6 = v6 && checkIpStars(ipv6);

		v6 = v6 && (ipv6.length == 8);
		return v6;
	}

	/**
	 * Format IPv6 NNNN:NNNN:NNNN:NNNN:NNNN:NNNN:NNNN:NNNN
	 * 
	 * @param sVal ip
	 * @return true if ok, or false if not valid
	 */
	public static boolean ipv6valid(String sVal)
	{
		return ipv6valid(sVal, false);
	}

	/**
	 * Format IPv4 NNN.NNN.NNN.NNN
	 * 
	 * @param sVal ip
	 * @param containsRegexp
	 *            allow to use regexp symbols : * and ?
	 * @return true if ok, or false if not valid
	 */
	public static boolean ipv4valid(String sVal, boolean containsRegexp)
	{
		String[] ipv4 = sVal.split("\\.");
		boolean v4 = true;

		for (int i = 0; i < ipv4.length; i++)
		{
			v4 = v4 && ipv4[i].length() < 4;
			boolean f = (ipv4[i].contains("*") || ipv4[i].contains("?")) && containsRegexp;
			v4 = v4 && Pattern.matches(f ? IP4_REGEXP : IP4, ipv4[i]);

		}
		// ip cannot be *.*.*.*
		v4 = v4 && checkIpStars(ipv4);

		v4 = v4 && (ipv4.length == 4);
		// split ignore last dot
		v4 = v4 && (!sVal.substring(sVal.length() - 1).equals(IP4_DELIMITER));
		return v4;
	}
        /**
         * Format IPv4 NNN.NNN.NNN.NNN
         * 
         * @param sVal ip
         * @return true if ok, or false if not valid
         */
	public static boolean ipv4valid(String sVal)
	{
		return ipv4valid(sVal, false);
	}

	/**
	 * Check that ip don't consist from only regexp symbols
	 * 
	 * @param ip
	 * @return true if ok
	 */
	private static boolean checkIpStars(String[] ip)
	{
		byte numberOfStars = 0;
		boolean valid = true;
		for (int i = 0; i < ip.length; i++)
		{
			if (ip[i].matches(ILLEGAL_IP_REGEXP))
				numberOfStars++;
		}
		if (numberOfStars == ip.length)
			valid = false;
		return valid;
	}

	/**
	 * Check port value
	 * 
	 * @param sVal
	 *            port
	 * @return true if ok, or false if not valid
	 */
	public static boolean checkPort(String sVal)
	{
		try
		{
			String trimmedValue = sVal.trim();
			int port = Integer.parseInt(trimmedValue);
			if ((port >= 0) && (port <= PORT_MAX_VALUE))
				return true;
		}
		catch (Throwable ignored)
		{
		}
		return false;
	}

	/**
         * Check that though one symbol include in a row
         * 
         * @param in string for checking
         * @param regexp symbols for checking
         * 
	 * @return true if ok
	 */
	public static boolean find(String in, String regexp)
	{
		return !in.matches("[^" + regexp + "]+");
	}
        
        /**
         * Check that string don't have os illegal symbols
         * 
         * @param str
         * @return 
         */
	public static boolean hasOsIllegalSymbols(String str)
	{
		return find(str, OS_ILLEGAL_SYMBOLS);
	}

	/**
	 * Check maximum full filename length
	 */
	public static boolean isValidLength(File f)
	{
		if (f == null)
			return false;
		String fullName = f.getName();
		int pos = fullName.lastIndexOf(".");
		String name = fullName.substring(0, pos);
		String ext = fullName.substring(pos + 1);
		String path = f.getParent();
		return isValidLength(path, name, ext);
	}

	/**
	 * Check maximum full filename length
	 */
	public static boolean isValidLength(String fileName, String path, String ext)
	{
		return fileName.length() <= filenameMaxLength(path, ext);
	}

	/**
	 * Check maximum full filename length
	 */
	public static int filenameMaxLength(String path, String ext)
	{
		int f = path.length();
		if ((ext != null) && !"".equals(ext))
		{
			f += ("." + ext).length();

			// Exel fix
			if ("xls".equals(ext) || "xlsx".equals(ext))
				return MAX_PATH_EXCEL - f;
		}
		return MAX_PATH - f;
	}

        /**
         * Check that string don't have two whitespaces together
         * 
         * @param str string for checking
         * @return true if ok
         */
	public static boolean check2whiteSpacesExisting(String str)
	{
		return str.matches(".+[\\s]{2,}.+");
	}
}
